"""
IR Node definitions using Pydantic models.

This module defines the intermediate representation (IR) node types that bridge
between C# Roslyn syntax and C++ code generation.
"""

from __future__ import annotations

from enum import Enum
from typing import Any, Optional

from pydantic import BaseModel, Field


class NodeType(str, Enum):
    """IR Node types"""

    CLASS_DECLARATION = "ClassDeclaration"
    METHOD_DECLARATION = "MethodDeclaration"
    PROPERTY_DECLARATION = "PropertyDeclaration"
    FIELD_DECLARATION = "FieldDeclaration"
    CONSTRUCTOR_DECLARATION = "ConstructorDeclaration"
    PARAMETER = "Parameter"
    STATEMENT = "Statement"
    EXPRESSION = "Expression"
    IF_STATEMENT = "IfStatement"
    FOREACH_STATEMENT = "ForeachStatement"
    RETURN_STATEMENT = "ReturnStatement"
    ASSIGNMENT_EXPRESSION = "AssignmentExpression"
    LITERAL_EXPRESSION = "LiteralExpression"


class IRNode(BaseModel):
    """
    Base class for all IR nodes.

    All IR nodes can be serialized to/from JSON and contain source location information.
    """

    node_type: NodeType
    source_file: Optional[str] = None
    line_number: Optional[int] = None
    metadata: dict[str, Any] = Field(default_factory=dict)

    class Config:
        """Pydantic configuration"""

        use_enum_values = True
        extra = "allow"


class Parameter(BaseModel):
    """Represents a method/constructor parameter"""

    name: str
    param_type: str
    default_value: Optional[str] = None


class ModifierFlags(str, Enum):
    """Common modifiers for declarations"""

    PUBLIC = "public"
    PRIVATE = "private"
    PROTECTED = "protected"
    INTERNAL = "internal"
    STATIC = "static"
    ABSTRACT = "abstract"
    VIRTUAL = "virtual"
    OVERRIDE = "override"
    SEALED = "sealed"
    READONLY = "readonly"
    CONST = "const"


class FieldDeclaration(IRNode):
    """Represents a field declaration"""

    node_type: NodeType = Field(default=NodeType.FIELD_DECLARATION, init=False)
    name: str
    field_type: str
    modifiers: list[str] = Field(default_factory=list)
    initializer: Optional[str] = None
    is_readonly: bool = False
    is_const: bool = False


class PropertyDeclaration(IRNode):
    """Represents a property declaration"""

    node_type: NodeType = Field(default=NodeType.PROPERTY_DECLARATION, init=False)
    name: str
    property_type: str
    modifiers: list[str] = Field(default_factory=list)
    has_getter: bool = True
    has_setter: bool = True
    getter_body: Optional[str] = None
    setter_body: Optional[str] = None
    is_auto_property: bool = True
    initializer: Optional[str] = None


class MethodDeclaration(IRNode):
    """Represents a method declaration"""

    node_type: NodeType = Field(default=NodeType.METHOD_DECLARATION, init=False)
    name: str
    return_type: str
    parameters: list[Parameter] = Field(default_factory=list)
    modifiers: list[str] = Field(default_factory=list)
    body: Optional[str] = None
    is_abstract: bool = False
    is_virtual: bool = False
    is_override: bool = False
    is_static: bool = False


class ConstructorDeclaration(IRNode):
    """Represents a constructor declaration"""

    node_type: NodeType = Field(default=NodeType.CONSTRUCTOR_DECLARATION, init=False)
    name: str
    parameters: list[Parameter] = Field(default_factory=list)
    modifiers: list[str] = Field(default_factory=list)
    body: Optional[str] = None
    initializer: Optional[str] = None  # Base or this constructor call


class ClassDeclaration(IRNode):
    """Represents a class declaration"""

    node_type: NodeType = Field(default=NodeType.CLASS_DECLARATION, init=False)
    name: str
    namespace: str
    modifiers: list[str] = Field(default_factory=list)
    base_types: list[str] = Field(default_factory=list)
    fields: list[FieldDeclaration] = Field(default_factory=list)
    properties: list[PropertyDeclaration] = Field(default_factory=list)
    methods: list[MethodDeclaration] = Field(default_factory=list)
    constructors: list[ConstructorDeclaration] = Field(default_factory=list)
    is_abstract: bool = False
    is_sealed: bool = False
    is_static: bool = False


# Statement IR Nodes


class Statement(IRNode):
    """Base class for statement IR nodes"""

    node_type: NodeType = Field(default=NodeType.STATEMENT, init=False)
    statement_kind: str  # "if", "foreach", "return", etc.


class IfStatement(Statement):
    """Represents an if statement"""

    node_type: NodeType = Field(default=NodeType.IF_STATEMENT, init=False)
    statement_kind: str = Field(default="if", init=False)
    condition: str
    then_block: str
    else_block: Optional[str] = None


class ForeachStatement(Statement):
    """Represents a foreach statement"""

    node_type: NodeType = Field(default=NodeType.FOREACH_STATEMENT, init=False)
    statement_kind: str = Field(default="foreach", init=False)
    variable_type: str
    variable_name: str
    collection: str
    body: str


class ReturnStatement(Statement):
    """Represents a return statement"""

    node_type: NodeType = Field(default=NodeType.RETURN_STATEMENT, init=False)
    statement_kind: str = Field(default="return", init=False)
    expression: Optional[str] = None


# Expression IR Nodes


class Expression(IRNode):
    """Base class for expression IR nodes"""

    node_type: NodeType = Field(default=NodeType.EXPRESSION, init=False)
    expression_kind: str
    expression_type: Optional[str] = None


class AssignmentExpression(Expression):
    """Represents an assignment expression"""

    node_type: NodeType = Field(default=NodeType.ASSIGNMENT_EXPRESSION, init=False)
    expression_kind: str = Field(default="assignment", init=False)
    left: str
    right: str
    operator: str = "="


class LiteralExpression(Expression):
    """Represents a literal expression"""

    node_type: NodeType = Field(default=NodeType.LITERAL_EXPRESSION, init=False)
    expression_kind: str = Field(default="literal", init=False)
    value: str
    literal_kind: str  # "string", "int", "bool", etc.
